﻿using System;
using System.Configuration;
using System.Data.SqlClient;
using System.IO;
using System.Transactions;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using Adex;
using SubSonic;


namespace MediaMonitor.Common
{

    public class AppUser : SiteUser
    {
        public static VSiteUser CurrentUser
        {
            get
            {
                if (HttpContext.Current.Session["CurrentUser"] != null)
                    return (VSiteUser)HttpContext.Current.Session["CurrentUser"];
                else
                    return new VSiteUser("SiteUserID", 0);
            }
            set { HttpContext.Current.Session["CurrentUser"] = value; }
        }

        public static int CurrUserID
        {
            get { return GetCurrentLoggedInUserId(); }
        }

        /// <summary>
        /// Add site user and roles + aspnet_membership details 
        /// </summary>
        /// <param name="Username"></param>
        /// <param name="Password"></param>
        /// <param name="Email"></param>
        /// <returns>returns the SiteUserID of newly added user</returns>
        public static int AddSiteUser(string Username, string Password, string Role, string Email, int CompanyCode,
                                      bool Active, out string errMsg)
        {
            var usrCont = new SiteUserController();

            errMsg = "";

            int uid = 0;

            ////check email duplication
            //if (AppUser.GetUserByEmail(Email.Trim()).SiteUserID > 0)
            //{
            //    errMsg = "This email already used by another user. try with some other email.";
            //    return 0;
            //}

            //check screen name
            if (Query().WHERE("UserName", Username).GetCount("SiteUserId") > 0)
            {
                errMsg = "User with this Username already exists. Write some different Username";
                return 0;
            }


            try
            {
                var status = new MembershipCreateStatus();
                MembershipUser memUsr = Membership.CreateUser(Username, Password.Trim(), Email.Trim(), "Q", "a", Active,
                                                              out status);


                switch (status)
                {
                    case MembershipCreateStatus.Success:
                        //add user to membership
                        var userGuid = (Guid)memUsr.ProviderUserKey;

                        //add this user to given role
                        Roles.AddUserToRole(memUsr.UserName, Role);

                        //'add this user to SiteUser Data table
                        var usr = new SiteUser();


                        usr.UserID = (Guid)memUsr.ProviderUserKey;
                        usr.Email = memUsr.Email;
                        usr.UserName = memUsr.UserName;

                        if (CompanyCode > 0)
                            usr.CompanyCode = CompanyCode;

                        string unlockCode = Guid.NewGuid().ToString().Replace("-", "").Substring(0, 6);
                        usr.UnlockCode = unlockCode;
                        usr.Active = Active;


                        //generate promotional code
                        string pCode = "";
                        //pCode = DateTime.Now.ToShortDateString.ToString.Trim.Replace("/", "")
                        pCode = DateTime.Now.Date.Day + DateTime.Now.Date.Month.ToString() +
                                DateTime.Now.Date.Year.ToString().Substring(2, 2);

                        pCode += DateTime.Now.Hour.ToString();
                        pCode += DateTime.Now.Minute.ToString();
                        pCode += DateTime.Now.Second.ToString();

                        usr.PromotionCode = pCode;

                        usr.IsLoggedIn = "false";
                        if (!Exists("Username", usr.UserName))
                            usr.Save();

                        uid = usr.SiteUserID;

                        if (uid <= 0)
                        {
                            errMsg = "Error!!! User not saved.. Contact Admin for this problem";
                            Membership.DeleteUser(memUsr.UserName);
                        }

                        break;


                    case MembershipCreateStatus.DuplicateEmail:
                    case MembershipCreateStatus.DuplicateUserName:
                        errMsg = "User with this email already exists. Please choose some other email for your new account.";
                        break;
                    case MembershipCreateStatus.InvalidPassword:
                        errMsg = "Wrong password format";
                        break;
                    case MembershipCreateStatus.InvalidUserName:
                        errMsg = "Invalid charachters found in username";
                        break;
                    default:
                        errMsg = status.ToString();
                        break;
                }
            }
            catch (Exception ex)
            {
                errMsg = errMsg + ". " + ex.Message;
                return 0;
            }


            return uid > 0 ? uid : 0;
        }

        /// <summary>
        /// Add site user and roles + aspnet_membership details 
        /// </summary>
        /// <param name="Username"></param>
        /// <param name="Password"></param>
        /// <param name="Email"></param>
        /// <returns>returns the SiteUserID of newly added user</returns>
        public static int AddSiteUserWithTransaction(string Username, string Password, string Role, string Email,
                                                     int CompanyCode, bool Active, out string errMsg)
        {
            var usrCont = new SiteUserController();

            errMsg = "";

            int uid = 0;

            ////check email duplication
            //if (AppUser.GetUserByEmail(Email.Trim()).SiteUserID > 0)
            //{
            //    errMsg = "This email already used by another user. try with some other email.";
            //    return 0;
            //}

            //check screen name
            if (Query().WHERE("UserName", Username).GetCount("SiteUserId") > 0)
            {
                errMsg = "User with this Username already exists. Write some different Username";
                return 0;
            }

            using (var ts = new TransactionScope(TransactionScopeOption.Required, TimeSpan.FromMinutes(10)))
            {
                using (var con = new SharedDbConnectionScope(ConfigurationManager.ConnectionStrings["DBAdex"].ToString()))
                {
                    try
                    {
                        var status = new MembershipCreateStatus();
                        MembershipUser memUsr = Membership.CreateUser(Username, Password.Trim(), Email.Trim(), "Q", "a",
                                                                      Active, out status);


                        switch (status)
                        {
                            case MembershipCreateStatus.Success:
                                //add user to membership
                                var userGuid = (Guid)memUsr.ProviderUserKey;

                                //add this user to given role
                                Roles.AddUserToRole(memUsr.UserName, Role);

                                //'add this user to SiteUser Data table
                                var usr = new SiteUser();


                                usr.UserID = (Guid)memUsr.ProviderUserKey;
                                usr.Email = memUsr.Email;
                                usr.UserName = memUsr.UserName;

                                if (CompanyCode > 0)
                                    usr.CompanyCode = CompanyCode;

                                string unlockCode = Guid.NewGuid().ToString().Replace("-", "").Substring(0, 6);
                                usr.UnlockCode = unlockCode;
                                usr.Active = Active;


                                //generate promotional code
                                string pCode = "";
                                //pCode = DateTime.Now.ToShortDateString.ToString.Trim.Replace("/", "")
                                pCode = DateTime.Now.Date.Day + DateTime.Now.Date.Month.ToString() +
                                        DateTime.Now.Date.Year.ToString().Substring(2, 2);

                                pCode += DateTime.Now.Hour.ToString();
                                pCode += DateTime.Now.Minute.ToString();
                                pCode += DateTime.Now.Second.ToString();

                                usr.PromotionCode = pCode;


                                if (!Exists("Username", usr.UserName))
                                    usr.Save();

                                uid = usr.SiteUserID;

                                if (uid <= 0)
                                {
                                    errMsg = "Error!!! User not saved.. Contact Admin for this problem";
                                    Membership.DeleteUser(memUsr.UserName);
                                }

                                break;


                            case MembershipCreateStatus.DuplicateEmail:
                            case MembershipCreateStatus.DuplicateUserName:
                                errMsg =
                                    "User with this email already exists. Please choose some other email for your new account.";
                                break;
                            case MembershipCreateStatus.InvalidPassword:
                                errMsg = "Wrong password format";
                                break;
                            case MembershipCreateStatus.InvalidUserName:
                                errMsg = "Invalid charachters found in username";
                                break;
                            default:
                                errMsg = status.ToString();
                                break;
                        }


                        ts.Complete();
                    }
                    catch (Exception ex)
                    {
                        con.Dispose();
                        ts.Dispose();
                        errMsg = errMsg + ". " + ex.Message;
                        return 0;
                    }
                }
            }


            return uid > 0 ? uid : 0;
        }


        public static SiteUser GetUserByUserName(string Username)
        {
            int uid = 0; bool IsLoggedIn;
            var rd = (SqlDataReader)FetchByParameter("UserName", Username);
            if (rd.HasRows)
            {
                rd.Read();
                uid = Convert.ToInt32(rd["SiteUserId"]);
                IsLoggedIn = Convert.ToBoolean(rd["IsLoggedIn"]);
                rd.Close();
            }
            var usr = new SiteUser(uid);
            return usr;
        }

        public static bool UpdateUser(int uid, string newUsername, string newPassword, out string errMsg)
        {
            errMsg = "";

            if (Matches("UserName", newUsername, "SiteUserId", uid.ToString()))
            {
                errMsg = "Another user / client already exists with this Username.";
                return false;
            }

            var usr = new SiteUser(uid);

            MembershipUser memUsr = Membership.GetUser(usr.UserID);
            if (memUsr.ChangePassword(memUsr.GetPassword(), newPassword))
            {
                return true;
            }


            return false;
        }

        public static SiteUser GetUserByEmail(string email)
        {
            int uid = 0;
            var rd = (SqlDataReader)FetchByParameter("Email", email);
            if (rd.HasRows)
            {
                rd.Read();
                uid = Convert.ToInt32(rd["SiteUserId"]);
                rd.Close();
            }
            var usr = new SiteUser(uid);
            return usr;
        }

        public static SiteUser GetByUserID(Guid guid)
        {
            int uid = 0;
            var rd = (SqlDataReader)FetchByParameter("UserID", guid.ToString());
            if (rd.HasRows)
            {
                rd.Read();
                uid = Convert.ToInt32(rd["SiteUserId"]);
                rd.Close();
            }

            var usr = new SiteUser(uid);
            return usr;
        }

        public static SiteUser GetCurUser()
        {
            int uid = 0;
            var rd = (SqlDataReader)FetchByParameter("Username", HttpContext.Current.User.Identity.Name);
            if (rd.HasRows)
            {
                rd.Read();
                uid = Convert.ToInt32(rd["SiteUserId"]);
                rd.Close();
            }


            var usr = new SiteUser(uid);
            return usr;
        }


        public static bool SignIn(int SiteUserID, bool SetAuthCookie)
        {
            // will return true if the user got successfully signed in
            //type may be "U" for user, "A" for Admin


            if (SiteUserID > 0)
            {
                var usr = new VSiteUser("SiteUserID", SiteUserID);
                //set Session Data
                CurrentUser = usr;
                HttpContext.Current.Session["UserID"] = usr.SiteUserID;
                HttpContext.Current.Session["Login"] = usr.UserName;
                HttpContext.Current.Session["Name"] = usr.FullName;
                HttpContext.Current.Session["Email"] = usr.Email;
                HttpContext.Current.Session["RoleName"] = usr.RoleName;
                HttpContext.Current.Session["CompanyCode"] = Utility.ToInt(usr.CompanyCode);
                HttpContext.Current.Session["CompanyName"] = Utility.ToStr(usr.CompanyName);

                //will act as default country selected every time this user logs in.
                SetCountry(AppUser.GetCountry(), AppUser.GetCountryName());

                HttpContext.Current.Session["UserCountryActive"] = Utility.ToBool(usr.UserCountryActive);


                //HttpContext.Current.Session("roles") = usr.Roles
                HttpContext.Current.Session["isLoggedIn"] = "true";

                //FormsAuthentication.RedirectFromLoginPage(usr.UserName, True)
                if (SetAuthCookie)
                {
                    FormsAuthentication.SetAuthCookie(usr.UserName, true);
                }
                else
                    FormsAuthentication.SetAuthCookie(usr.UserName, false);

                return true;
            }
            else
            {
                throw new Exception("No user withiout a valid SiteUserID can be Sign In");
            }
        }

        public static bool SignOut(int UserID)
        {
            // will return true if the user got successfully signed out
            //type may be "C" for Customer, "A" for Admin

            FormsAuthentication.SignOut();

            HttpContext.Current.Session.Abandon();
            HttpContext.Current.Session.Contents.RemoveAll();

            // HttpContext.Current.Session("currUser") = Nothing
            HttpContext.Current.Session["UserID"] = "";
            HttpContext.Current.Session["Login"] = "";
            HttpContext.Current.Session["Name"] = "";
            HttpContext.Current.Session["Email"] = "";
            HttpContext.Current.Session["Roles"] = "";

            HttpContext.Current.Session["CompanyCode"] = "0";
            HttpContext.Current.Session["CompanyName"] = "";

            HttpContext.Current.Session["isLoggedIn"] = "false";

            HttpContext.Current.Session["UserCountryID"] = null;
            HttpContext.Current.Session["UserCountryName"] = null;
           
            //HttpContext.Current.Response.Redirect(HomePage)
            return true;
        }


        private static int CheckMembershipUserLogin()
        {
            //check if aspnet_membership session is still running then
            //logged in that user programatically
            if (!HttpContext.Current.User.Identity.IsAuthenticated)
            {
                return 0;
            }

            MembershipUser memUsr = Membership.GetUser();

            if ((memUsr != null))
            {
                return GetByUserID((Guid)memUsr.ProviderUserKey).SiteUserID;
            }
            else
            {
                //return 0;
            }

            if (HttpContext.Current.User.Identity.IsAuthenticated && (Membership.GetUser().ProviderUserKey != null))
            {
                //it means aspnet_membership session is running and valid
                //so signin again that lost user
                var usr = new SiteUser(GetByUserID((Guid)Membership.GetUser().ProviderUserKey).SiteUserID);

                SignIn(usr.SiteUserID, true);

                //return the SiteUserID

                return usr.SiteUserID;
            }
            else
            {
                //return 0 indicating no user signin .. or no member session running.
                return 0;
            }
        }

        private static int CheckMembershipUserLogin(int siteUserID)
        {
            //check if aspnet_membership session is still running then
            //logged in that user programatically

            if (HttpContext.Current.User.Identity.IsAuthenticated && (Membership.GetUser().ProviderUserKey != null) &&
                (int)Membership.GetUser().ProviderUserKey == siteUserID)
            {
                //it means aspnet_membership session is running and valid
                //so signin again that lost user

                SignIn(siteUserID, true);

                //return the SiteUserID
                return siteUserID;
            }
            else
            {
                //return 0 indicating no user signin .. or no member session running.
                return 0;
            }
        }

        // If User is logged in, return user's id... otherwise return 0 or false
        public static int IsUserLoggedIn()
        {
            try
            {
                if (HttpContext.Current.Session["isLoggedIn"] == null)
                {
                    return CheckMembershipUserLogin();
                }

                if (HttpContext.Current.Session["isLoggedIn"].ToString() == "true")
                {
                    return Convert.ToInt32(HttpContext.Current.Session["UserID"]);
                }
                else
                {
                    return CheckMembershipUserLogin();
                    //Return 0
                }
            }
            catch
            {
                return 0;
            }
        }

        // If given User is logged in, return user's id... otherwise return 0 or false
        public static int IsUserLoggedIn(int siteUserID, bool forcedSignIn)
        {
            try
            {
                if ((HttpContext.Current.Session["isLoggedIn"] == null) && (HttpContext.Current.Session["UserID"] == null) &&
                    Convert.ToString(HttpContext.Current.Session["UserID"]) == siteUserID.ToString() &&
                    Convert.ToString(HttpContext.Current.Session["isLoggedIn"]) == "true")
                {
                    return Convert.ToInt32(HttpContext.Current.Session["UserID"]);
                }
                else
                {
                    if (forcedSignIn)
                    {
                        return CheckMembershipUserLogin(siteUserID);
                    }
                    return 0;
                }
            }
            catch
            {
                return CheckMembershipUserLogin();
            }
        }

        public static int GetCurrentLoggedInUserId()
        {
            if ((HttpContext.Current.Session["UserID"] != null))
            {
                if (HttpContext.Current.Session["UserId"].ToString().Length > 0)
                {
                    if (Convert.ToInt32(HttpContext.Current.Session["UserID"]) > 0)
                        return Convert.ToInt32(HttpContext.Current.Session["UserId"]);

                    else
                        return 0;
                }
                else
                    return 0;
            }
            else
            {
                int uid = IsUserLoggedIn();
                if (uid > 0)
                {
                    HttpContext.Current.Session["UserID"] = uid;
                }
                return uid;
            }
        }

        public static int ValidateUser(Page url, bool forbidden)
        {
            int uid = 0;
            uid = IsUserLoggedIn();

            if (!(uid > 0))
            {
                if (forbidden)
                    HttpContext.Current.Response.Redirect("~/access-denied.aspx?uid=" + uid + "&ReturnUrl=" +
                                                          url.Request.ServerVariables["SCRIPT_NAME"]);
            }

            return uid;
        }


        public static bool Unlock(int siteUserID, byte type)
        {
            var usr = new SiteUser("SiteUserId", siteUserID);

            MembershipUser memUsr = Membership.GetUser(usr.UserID);

            memUsr.IsApproved = true;
            usr.Active = true;
            usr.Save();


            switch (type)
            {
                case 1:
                    //add admin role
                    if (!Roles.IsUserInRole(memUsr.UserName, "admin"))
                    {
                        Roles.AddUserToRole(memUsr.UserName, "admin");
                    }
                    break;
                case 2:
                    //add company role
                    if (!Roles.IsUserInRole(memUsr.UserName, "company"))
                    {
                        Roles.AddUserToRole(memUsr.UserName, "company");
                    }
                    break;
                case 3:
                    //add user role
                    if (!Roles.IsUserInRole(memUsr.UserName, "user"))
                    {
                        Roles.AddUserToRole(memUsr.UserName, "user");
                    }

                    break;
            }

            Membership.UpdateUser(memUsr);
            //update membership user.

            return true;
        }


        public static bool DeleteSiteUser(string userName)
        {
            if (Membership.DeleteUser(userName))
                return true;
            else
                return false;
        }

        public static bool DeleteSiteUser(SiteUser usr)
        {
            if (Membership.DeleteUser(usr.UserName))
                return true;
            else
                return false;
        }

        public static bool SetSiteUserActivation(SiteUser usr, bool active)
        {
            MembershipUser memUsr = Membership.GetUser(usr.UserName);

            memUsr.IsApproved = active;

            var q = new Update(Schema);
            q.Set("Active").EqualTo(active);
            q.Where("SiteUserId").IsEqualTo(usr.SiteUserID);
            if (q.Execute() > 0)
            {
                Membership.UpdateUser(memUsr);
                return true;
            }
            else
                return false;
        }


        public static string[] GetUserRoles(int uid)
        {
            if (uid == 0) return new[] { "" };

            var usr = new SiteUser(uid);
            MembershipUser memUser = Membership.GetUser(usr.UserID);

            if (memUser == null)
                return new string[] { "" };

            string[] roles = Roles.GetRolesForUser(memUser.UserName);
            return roles;
        }


        public static bool IsInRole(int uid, string role)
        {
            var usr = new SiteUser(uid);
            MembershipUser memUser = Membership.GetUser(usr.UserID);

            return Roles.IsUserInRole(memUser.UserName, role);
        }

        public static bool IsInRole(string username, string role)
        {
            return Roles.IsUserInRole(username, role);
        }

        public static bool Exists(string ColumnName, string Value)
        {
            var usr = new SiteUser(ColumnName, Value);
            if (usr.SiteUserID > 0)
            {
                return true;
            }
            else
            {
                return false;
            }
        }


        public static bool Matches(string columnName, string value, string excludingColumn, string excludingValue)
        {
            int retval =
                Query().WHERE(columnName, value).AND(excludingColumn, Comparison.NotEquals, excludingValue).GetCount(
                    "SiteUserId");

            if (retval > 0)
            {
                return true;
                //match exists
            }
            else
            {
                return false;
                //match doesn't exists
            }
        }

        public static int Register(SiteUser user)
        {
            if (!Exists("Username", user.UserName))
            {
                user.Save();

                //do something important on registering new user.

                return user.SiteUserID;
            }
            else
                return 0;
        }

        #region "User Country"

        public static byte GetCurrentCountryByIp()
        {
            return Utility.DefaultCountry;

            /*
            var Ip2Country = new IPToCountry();

            string sApplicationPath = HttpContext.Current.Server.MapPath("~");

            string name1 = sApplicationPath + @"\IP2CountryResource\apnic.latest";
            string name2 = sApplicationPath + @"\IP2CountryResource\arin.latest";
            string name3 = sApplicationPath + @"\IP2CountryResource\lacnic.latest";
            string name4 = sApplicationPath + @"\IP2CountryResource\ripencc.latest";


            var s1 = new FileStream(name1, FileMode.Open);
            var sr1 = new StreamReader(s1);
            Ip2Country.Load(sr1);
            sr1.Close();
            s1.Close();

            var s2 = new FileStream(name2, FileMode.Open);
            var sr2 = new StreamReader(s2);
            Ip2Country.Load(sr2);
            sr2.Close();
            s2.Close();

            var s3 = new FileStream(name3, FileMode.Open);
            var sr3 = new StreamReader(s3);
            Ip2Country.Load(sr3);
            sr3.Close();
            s3.Close();

            var s4 = new FileStream(name4, FileMode.Open);
            var sr4 = new StreamReader(s4);
            Ip2Country.Load(sr4);
            sr4.Close();
            s4.Close();

            #region Finding Visitors IP Address

            string visitorsIpAddr = string.Empty;
            //Users IP Address.                
            if (HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"] != null)
            {
                //To get the IP address of the machine and not the proxy
                visitorsIpAddr = HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
            }
            else if (HttpContext.Current.Request.UserHostAddress.Length != 0)
            {
                visitorsIpAddr = HttpContext.Current.Request.UserHostAddress;
            }

            #endregion

            string visitorsCountry = Ip2Country.GetCountry(visitorsIpAddr);

        
            //find country id from DB
            byte countryId =
                Utility.ToByte(Country.Query().SetSelectList("CountryID").WHERE("TLD", visitorsCountry).AND("Active", true).ExecuteScalar(), Utility.DefaultCountry);

            return countryId;
             */

        }


        public static byte GetCountry()
        {

            return Utility.DefaultCountry;

        }

        public static string GetCountryName()
        {
            return Adex.Country.Query().SetSelectList("CountryName").WHERE("CountryID", Utility.DefaultCountry).ExecuteScalar().ToString();
        }


        public static void SetCountry(byte countryId, string countryName)
        {
            HttpContext.Current.Session["UserCountryID"] = countryId;
            HttpContext.Current.Session["UserCountryName"] = countryName;


        }

        public static bool IsValidCountry(byte countryID, Enums.Countries country)
        {
            if (countryID == Utility.ToByte(country))
                return true;
            else
                return false;
        }

        public static bool IsCountry_DO() { return Utility.DefaultCountry == Utility.ToByte(Enums.Countries.DO.GetHashCode()) ? true : false; }
        public static bool IsCountry_PR() { return Utility.DefaultCountry == Utility.ToByte(Enums.Countries.PR.GetHashCode()) ? true : false; }
        public static bool IsCountry_TT() { return Utility.DefaultCountry == Utility.ToByte(Enums.Countries.TT.GetHashCode()) ? true : false; }
        public static bool IsCountry_VE() { return Utility.DefaultCountry == Utility.ToByte(Enums.Countries.VE.GetHashCode()) ? true : false; }

        #endregion
    }

}